package com.tengfei.main.plan.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tengfei.common.constant.UserConstants;
import com.tengfei.common.core.domain.PageQuery;
import com.tengfei.common.core.page.TableDataInfo;
import com.tengfei.common.helper.DataBaseHelper;
import com.tengfei.common.utils.StringUtils;
import com.tengfei.main.course.domain.Chapter;
import com.tengfei.main.course.domain.ChapterVideo;
import com.tengfei.main.course.domain.Course;
import com.tengfei.main.course.domain.Video;
import com.tengfei.main.course.mapper.ChapterMapper;
import com.tengfei.main.course.mapper.ChapterVideoMapper;
import com.tengfei.main.course.mapper.CourseMapper;
import com.tengfei.main.course.mapper.VideoMapper;
import com.tengfei.main.plan.domain.PlanCourses;
import com.tengfei.main.plan.domain.UsersCourse;
import com.tengfei.main.plan.domain.bo.StudyMapBo;
import com.tengfei.main.plan.domain.vo.UserChapterProgressVo;
import com.tengfei.main.plan.domain.vo.UserCourseProgressVo;
import com.tengfei.main.plan.domain.vo.UserPlanProgressVo;
import com.tengfei.main.plan.mapper.PlanCoursesMapper;
import com.tengfei.main.plan.mapper.UserCoursesMapper;
import com.tengfei.main.plan.service.IStudyMapService;
import com.tengfei.main.system.domain.SysDept;
import com.tengfei.main.system.domain.SysUser;
import com.tengfei.main.system.mapper.SysDeptMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 用户课程Service业务层处理
 *
 * @author tengfei
 * @date 2022-08-01
 */
@Service
public class StudyMapServiceImpl implements IStudyMapService {

    @Resource
    private UserCoursesMapper baseMapper;
    @Resource
    private PlanCoursesMapper planCourseMapper;
    @Resource
    private ChapterMapper chapterMapper;
    @Resource
    private ChapterVideoMapper chapterVideoMapper;
    @Resource
    private VideoMapper videoMapper;
    @Resource
    private SysDeptMapper deptMapper;
    @Resource
    private CourseMapper courseMapper;


    /**
     * 查询当前学习计划下某个用户完成进度情况
     */
    @Override
    public TableDataInfo<UserPlanProgressVo> queryUserPlanProgress(StudyMapBo studyMapBo, PageQuery pageQuery) {
        Page<UserPlanProgressVo> userPlanProgressVoPage = baseMapper.selectPlanUsers(pageQuery.build(), buildQueryWrapperUser(studyMapBo));
        // 查询进度
        userPlanProgressVoPage.getRecords().forEach(userPlanProgressVo -> {
            // 查询学习计划下课程id列表
            List<Long> courseIds = planCourseMapper.selectList(new LambdaQueryWrapper<PlanCourses>()
                    .eq(PlanCourses::getPlanId, studyMapBo.getPlanId()))
                    .stream().map(planCourses -> planCourses.getCourseId())
                    .collect(Collectors.toList());
            // 总视频数
            int allVideos = getVideos4Plan(courseIds);
            // 查询学习计划下已观看视频记录
            AtomicInteger viewVideos = new AtomicInteger(0);
            courseIds.forEach(courseId -> {
                UsersCourse usersCourse = baseMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                        .eq(UsersCourse::getUserId, userPlanProgressVo.getUserId())
                        .eq(UsersCourse::getCourseId, courseId));
                if (ObjectUtil.isNotNull(usersCourse)) {
                    Integer videos4User = getVideos4User(usersCourse);
                    viewVideos.getAndAdd(videos4User);
                }
            });
            // 计算学习计划完成率
            double progress = (allVideos != 0 ? viewVideos.get() * 100.0 / allVideos : 0);
            userPlanProgressVo.setProgress(progress);
        });
        return TableDataInfo.build(userPlanProgressVoPage);
    }

    /**
     * 导出学习进度
     *
     * @param studyMapBo
     * @return
     */
    @Override
    public List<UserPlanProgressVo> queryList(StudyMapBo studyMapBo) {
        List<UserPlanProgressVo> userPlanProgressVoPage = baseMapper.selectPlanUsers2Export(buildQueryWrapperUser(studyMapBo));
        // 查询进度
        userPlanProgressVoPage.forEach(userPlanProgressVo -> {
            // 查询学习计划下课程id列表
            List<Long> courseIds = planCourseMapper.selectList(new LambdaQueryWrapper<PlanCourses>()
                    .eq(PlanCourses::getPlanId, studyMapBo.getPlanId()))
                    .stream().map(planCourses -> planCourses.getCourseId())
                    .collect(Collectors.toList());
            // 总视频数
            int allVideos = getVideos4Plan(courseIds);
            // 查询学习计划下已观看视频记录
            AtomicInteger viewVideos = new AtomicInteger(0);
            courseIds.forEach(courseId -> {
                UsersCourse usersCourse = baseMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                        .eq(UsersCourse::getUserId, userPlanProgressVo.getUserId())
                        .eq(UsersCourse::getCourseId, courseId));
                if (ObjectUtil.isNotNull(usersCourse)) {
                    Integer videos4User = getVideos4User(usersCourse);
                    viewVideos.getAndAdd(videos4User);
                }
            });
            // 计算学习计划完成率
            double progress = (allVideos != 0 ? viewVideos.get() * 100.0 / allVideos : 0);
            userPlanProgressVo.setProgress(progress);
        });
        return userPlanProgressVoPage;
    }

    /**
     * 查询当前学习计划下某个用户某门课程的完成情况
     */
    @Override
    public List<UserCourseProgressVo> queryUserCourseProgress(Long userId, Long planId) {
        List<UserCourseProgressVo> progressVos = new ArrayList<>();
        // 查询学习计划下的课程列表
        planCourseMapper.selectList(new LambdaQueryWrapper<PlanCourses>()
                .eq(PlanCourses::getPlanId, planId))
                .stream().map(planCourse -> planCourse.getCourseId())
                .forEach(courseId -> {
                    // 查询课程信息
                    Course course = courseMapper.selectById(courseId);
                    UserCourseProgressVo progressVo = BeanUtil.copyProperties(course, UserCourseProgressVo.class);
                    // 查询课程进度
                    UsersCourse usersCourse = baseMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                            .eq(UsersCourse::getUserId, userId)
                            .eq(UsersCourse::getCourseId, courseId));
                    int allVideos = getVideos4Course(courseId);
                    int viewVideos = ObjectUtil.isNotNull(usersCourse) ? getVideos4User(usersCourse) : 0;
                    // 计算学习计划完成率
                    double progress = (allVideos != 0 ? viewVideos * 100.0 / allVideos : 0);
                    progressVo.setProgress(progress);
                    progressVos.add(progressVo);
                });
        return progressVos;
    }

    /**
     * 查询当前学习计划下某门课程某个用户的各个章节完成情况
     */
    @Override
    public List<UserChapterProgressVo> queryUserChapterProgress(Long userId, Long courseId) {
        List<UserChapterProgressVo> progressVos = new ArrayList<>();
        // 该课程的观看历史
        UsersCourse usersCourse = baseMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                .eq(UsersCourse::getCourseId, courseId)
                .eq(UsersCourse::getUserId, userId));
        // 是否已到达观看章节
        AtomicBoolean viewingChapter = new AtomicBoolean(false);
        // 查询课程章节列表
        chapterMapper.selectList(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, courseId)
                .orderByAsc(Chapter::getChapterLevel))
                .forEach(chapter -> {
                    UserChapterProgressVo progressVo = new UserChapterProgressVo();
                    progressVo.setChapterId(chapter.getChapterId());
                    progressVo.setChapterName(chapter.getChapterName());
                    if (ObjectUtil.isNotNull(usersCourse)) {
                        if (!usersCourse.getChapterId().equals(chapter.getChapterId())) {
                            if (viewingChapter.get()) {
                                progressVo.setProgress(0.0);
                            } else {
                                progressVo.setProgress(100.0);
                            }
                        } else {
                            viewingChapter.set(true);
                            if (usersCourse.getChapterFinish() == 1) {
                                progressVo.setProgress(100.0);
                            } else {
                                // 总秒数
                                int allSeconds = 0;
                                // 观看秒数
                                int viewSeconds = 0;
                                // 获取章节下视频
                                List<ChapterVideo> chapterVideos = chapterVideoMapper.selectList(new LambdaQueryWrapper<ChapterVideo>()
                                        .eq(ChapterVideo::getChapterId, chapter.getChapterId())
                                        .orderByAsc(ChapterVideo::getLevel));
                                // 是否已到达观看视频
                                boolean isToView = false;
                                for (ChapterVideo chapterVideo : chapterVideos) {
                                    // 查询视频信息
                                    Video video = videoMapper.selectById(chapterVideo.getVideoId());
                                    allSeconds += video.getVideoDuration();
                                    if (!video.getVideoId().equals(usersCourse.getVideoId())) {
                                        if (!isToView) {
                                            viewSeconds += video.getVideoDuration();
                                        }
                                    } else {
                                        // 已到达观看视频
                                        isToView = true;
                                        if (usersCourse.getVideoFinish() == 1) {
                                            viewSeconds += video.getVideoDuration();
                                        } else {
                                            viewSeconds += usersCourse.getVideoNowDuration();
                                        }
                                    }
                                }
                                progressVo.setProgress(viewSeconds * 100.0 / allSeconds);
                            }
                        }
                    } else {
                        progressVo.setProgress(0.0);
                    }
                    progressVos.add(progressVo);
                });
        return progressVos;
    }


    private Wrapper<SysUser> buildQueryWrapperUser(StudyMapBo studyMapBo) {
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper
                .apply("s.plan_id=" + studyMapBo.getPlanId())
                .eq("u.show_status", UserConstants.USER_NORMAL)
                .eq("u.status", UserConstants.USER_NORMAL)
                .like(StringUtils.isNotBlank(studyMapBo.getName()), "u.name", studyMapBo.getName())
                .and(ObjectUtil.isNotNull(studyMapBo.getDeptId()), w -> {
                    List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
                            .select(SysDept::getDeptId)
                            .apply(DataBaseHelper.findInSet(studyMapBo.getDeptId(), "ancestors")));
                    List<Long> ids = deptList.stream().map(SysDept::getDeptId).collect(Collectors.toList());
                    ids.add(studyMapBo.getDeptId());
                    w.in("u.dept_id", ids);
                });
        return wrapper;
    }

    /**
     * 获取某个用户某个视频已观看视频数
     */
    private Integer getVideos4User(UsersCourse userCourse) {
        int videoCount = 0;
        // 获取章节数
        List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, userCourse.getCourseId())
                .orderByAsc(Chapter::getChapterLevel));
        for (int i = 0; i < chapters.size(); i++) {
            if (!chapters.get(i).getChapterId().equals(userCourse.getChapterId())) {
                // 说明未到该章节，获取章节视频
                Integer chapterVideoCount = chapterMapper.selectById(chapters.get(i)
                        .getChapterId()).getChapterVideoCount();
                videoCount += chapterVideoCount;
            } else {
                if (userCourse.getChapterFinish() == 1) {
                    // 该章节看完
                    // 说明未到该章节，获取章节视频
                    Integer chapterVideoCount = chapterMapper.selectById(chapters.get(i)
                            .getChapterId()).getChapterVideoCount();
                    videoCount += chapterVideoCount;
                    return videoCount;
                } else {
                    // 章节视频未看完
                    List<ChapterVideo> chapterVideos = chapterVideoMapper.selectList(new LambdaQueryWrapper<ChapterVideo>()
                            .eq(ChapterVideo::getChapterId, chapters.get(i).getChapterId())
                            .orderByAsc(ChapterVideo::getLevel));
                    int count = 0;
                    for (ChapterVideo chapterVideo : chapterVideos) {
                        if (!userCourse.getVideoId().equals(chapterVideo.getVideoId())) {
                            count++;
                        } else {
                            if (userCourse.getVideoFinish() == 1) {
                                // 该视频已看完
                                count++;
                            }
                            videoCount += count;
                            return videoCount;
                        }
                    }
                }
            }
        }
        return videoCount;
    }

    /**
     * 获取某个学习计划下的视频数
     */
    private Integer getVideos4Plan(List<Long> courseIds) {
        // 因为局部变量无法在匿名内部类中被操作，构造一个原子化int对象，线程安全
        AtomicInteger countVideo = new AtomicInteger();
        courseIds.forEach(courseId -> {
            // 获取每个课程下的章节数
            List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>()
                    .eq(Chapter::getCourseId, courseId));
            // 获取每个章节下的视频数
            chapters.forEach(chapter -> {
                // 累加
                countVideo.getAndAdd(chapter.getChapterVideoCount());
            });
        });
        return countVideo.get();
    }

    /**
     * 获取某个课程下的视频数
     */
    private Integer getVideos4Course(Long courseId) {
        int countVideo = 0;
        // 获取每个课程下的章节数
        List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, courseId));
        // 获取每个章节下的视频数
        for (Chapter chapter : chapters) {
            countVideo += chapter.getChapterVideoCount();
        }

        return countVideo;
    }

}
